package org.blogwu.learn.jvmlearn.class1;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class MyTest16 extends ClassLoader {

    private String classLoadName;

    private final String fileExtension = ".class";

    private String path = "";


    public void setPath(String path) {
        this.path = path;
    }


    public MyTest16(String classLoadName) {
        super();
        this.classLoadName = classLoadName;
    }

    public MyTest16(ClassLoader parent, String classLoadName) {
        super(parent);
        this.classLoadName = classLoadName;
    }


    @Override
    public String toString() {
        return classLoadName + " {" +
                "classLoadName='" + classLoadName + '\'' +
                '}';
    }

    private byte[] loadClassData(String className) {
        // InputStream is=null;
        byte[] data = null;
        // ByteArrayOutputStream baos=null;
//        System.out.println(path + className + this.fileExtension);
        className = className.replace(".", "\\");
        try (InputStream is = new FileInputStream(new File(path + className + this.fileExtension));
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            //
            int ch = 0;
            while (-1 != (ch = is.read())) {
                baos.write(ch);
            }
            data = baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] b = loadClassData(name);
        return defineClass(name, b, 0, b.length);
    }


    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InterruptedException {
        //test1();
        test2();
    }


    /**
     * 类卸载  -XX:+TraceClassUnloading
     *
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static void test2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, InterruptedException {

        MyTest16 test12 = new MyTest16("org.blogwu.learn.jvmlearn.class1");
        test12.setPath("D:\\");
        Class<?> cls12 = test12.loadClass("MyTest1");
        Object o12 = cls12.newInstance();
        System.out.println(cls12.hashCode());


        test12 = null;
        cls12 = null;
        o12 = null;

        Thread.sleep(20000);
        System.gc();


        test12 = new MyTest16("org.blogwu.learn.jvmlearn.class1");
        test12.setPath("D:\\");
        cls12 = test12.loadClass("MyTest1");
        o12 = cls12.newInstance();
        System.out.println(cls12.hashCode());

        Thread.sleep(20000);

    }


    public static void test1() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        {
            // 这个类在class Path下  会被系统加载器加载   因为下面加载类的完整名称在系统加载器中以存在,所以不会执行自定义加载器
//            MyTest16 test = new MyTest16("org.blogwu.learn.jvmlearn.class1");
//            test.setPath("C:\\product\\learnProject\\jvm_learn\\target\\classes\\org\\blogwu\\jvm_learn\\jvmlearn\\class1\\");
//            Class<?> cls = test.loadClass("org.blogwu.learn.jvmlearn.class1.MyTest1");
//            Object o = cls.newInstance();
//            System.out.println(cls.hashCode());
//            System.out.println(cls.getClassLoader());
        }


        /**
         * 加载class path路径下的类
         * 注:类的完整名字应该是  包名+类名称
         */
        {
            MyTest16 test1 = new MyTest16("org.blogwu.learn.jvmlearn.class1");
            Class<?> cls1 = test1.loadClass("org.blogwu.learn.jvmlearn.class1.MyTest1");
            Object o1 = cls1.newInstance();
            System.out.println(cls1.hashCode());
            System.out.println(cls1.getClassLoader());

            MyTest16 test2 = new MyTest16("org.blogwu.learn.jvmlearn.class1");
            Class<?> cls2 = test2.loadClass("org.blogwu.learn.jvmlearn.class1.MyTest1");
            Object o2 = cls2.newInstance();
            System.out.println(cls2.hashCode());
            System.out.println(cls2.getClassLoader());
            System.out.println(cls2.isInstance(cls1));
        }

        System.out.println("----------------------------------------------------------------------");


        /**
         * 加载非classPath路径下的类
         */
        {
            MyTest16 test11 = new MyTest16("org.blogwu.learn.jvmlearn.class1");
            test11.setPath("D:\\");
            //D:\  org.blogwu.learn.jvmlearn.class1.MyTest1
            Class<?> cls11 = test11.loadClass("MyTest1");
            Object o11 = cls11.newInstance();
            System.out.println(cls11.hashCode());
            System.out.println(cls11.getClassLoader());


            MyTest16 test12 = new MyTest16("org.blogwu.learn.jvmlearn.class1");
            test12.setPath("D:\\");
            //D:\  org.blogwu.learn.jvmlearn.class1.MyTest1
            Class<?> cls12 = test12.loadClass("MyTest1");
            Object o12 = cls12.newInstance();
            System.out.println(cls12.hashCode());
            System.out.println(cls12.getClassLoader());
            System.out.println(cls11.isInstance(cls12));


            MyTest16 test13 = new MyTest16(test12, "org.blogwu.learn.jvmlearn.class1");
            test13.setPath("D:\\");
            //D:\  org.blogwu.learn.jvmlearn.class1.MyTest1
            Class<?> cls13 = test13.loadClass("MyTest1");
            Object o13 = cls13.newInstance();
            System.out.println(cls13.hashCode());
            System.out.println(cls13.getClassLoader());
            System.out.println(cls13.isInstance(cls12));
        }


    }

}
